package com.rtx.edi.platform.application.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rtx.edi.model.application.dto.PlApplicationLinkDtlDto;
import com.rtx.edi.model.application.dto.PlApplicationLinkDto;
import com.rtx.edi.model.application.po.PlApplication;
import com.rtx.edi.model.application.po.PlApplicationEnvironment;
import com.rtx.edi.model.application.po.PlApplicationLink;
import com.rtx.edi.model.application.po.PlApplicationLinkDtl;
import com.rtx.edi.model.company.po.PlCompany;
import com.rtx.edi.platform.application.mapper.PlApplicationEnvironmentMapper;
import com.rtx.edi.platform.application.mapper.PlApplicationLinkDtlMapper;
import com.rtx.edi.platform.application.mapper.PlApplicationLinkMapper;
import com.rtx.edi.platform.application.mapper.PlApplicationMapper;
import com.rtx.edi.platform.application.service.PlApplicationLinkService;
import com.rtx.edi.platform.company.mapper.PlCompanyMapper;

/**
 * <p>
 * 应用关联表  服务实现类
 * </p>
 *
 * @author wq
 * @since 2023-03-14
 */
@Service
public class PlApplicationLinkServiceImpl extends ServiceImpl<PlApplicationLinkMapper, PlApplicationLink> implements PlApplicationLinkService {

    @Autowired
    private PlApplicationLinkDtlMapper plApplicationLinkDtlMapper;
    
    @Autowired
    PlApplicationMapper plApplicationMapper;
    
    @Autowired
    PlCompanyMapper plCompanyMapper;
    
    @Autowired
    PlApplicationEnvironmentMapper plApplicationEnvironmentMapper;
    

    @Override
	public List<Map<String, Object>> selectPlAppLinkDtlSelector(PlApplicationLinkDto dto) {
    	QueryWrapper<PlApplicationLinkDtl> qw = new QueryWrapper<PlApplicationLinkDtl>();
    	qw.eq("link_id", dto.getId());
    	List<PlApplicationLinkDtl>  list = plApplicationLinkDtlMapper.selectList(qw);
    	List<Map<String,Object>> selectorList = new ArrayList<>(); 
    	for(PlApplicationLinkDtl dtl:list) {
    		Map<String,Object> temp = new HashMap<String, Object>();
    		temp.put("id", dtl.getId());
    		temp.put("linkName", dtl.getAboveEnvironmentName()+"<->"+dtl.getBelowEnvironmentName());
    		selectorList.add(temp);
    	}
		return selectorList;
	}



	@Override
	public List<Map<String, Object>> selectPlAppLinkSelector() {
    	QueryWrapper<PlApplicationLink> qw = new QueryWrapper<PlApplicationLink>();
    	List<PlApplicationLink>  list = baseMapper.selectList(qw);
    	List<Map<String,Object>> selectorList = new ArrayList<>(); 
    	for(PlApplicationLink link:list) {
    		Map<String,Object> temp = new HashMap<String, Object>();
    		temp.put("id", link.getId());
    		temp.put("linkName", link.getLinkName()+"");
    		selectorList.add(temp);
    	}
		return selectorList;
	}
    
    

	@Override
    public void selectPlApplicationList(Page<PlApplicationLink> pageParam, PlApplicationLink plApplicationLink) {
        LambdaQueryWrapper<PlApplicationLink> query = new LambdaQueryWrapper<>();
        query.orderByDesc(PlApplicationLink::getId);
        if(plApplicationLink != null){
            query.eq(plApplicationLink.getCompanyId() != null,PlApplicationLink::getCompanyId,plApplicationLink.getCompanyId())
                    .like(plApplicationLink.getLinkName() != null,PlApplicationLink::getLinkName,plApplicationLink.getLinkName())
                    .eq(plApplicationLink.getLinkStatus() != null,PlApplicationLink::getLinkStatus,plApplicationLink.getLinkStatus())
                    .eq(plApplicationLink.getAboveCompanyId() != null,PlApplicationLink::getAboveCompanyId,plApplicationLink.getAboveCompanyId())
                    .like(plApplicationLink.getAboveCompanyNo() != null,PlApplicationLink::getAboveCompanyNo,plApplicationLink.getAboveCompanyNo())
                    .like(plApplicationLink.getAboveCompanyName() != null,PlApplicationLink::getAboveCompanyName,plApplicationLink.getAboveCompanyName())
                    .eq(plApplicationLink.getAboveApplicationId() != null,PlApplicationLink::getAboveApplicationId,plApplicationLink.getAboveApplicationId())
                    .like(plApplicationLink.getAboveApplicationNo() != null,PlApplicationLink::getAboveApplicationNo,plApplicationLink.getAboveApplicationNo())
                    .like(plApplicationLink.getAboveApplicationName() != null,PlApplicationLink::getAboveApplicationName,plApplicationLink.getAboveApplicationName())
                    .eq(plApplicationLink.getBelowCompanyId() != null,PlApplicationLink::getBelowCompanyId,plApplicationLink.getBelowCompanyId())
                    .like(plApplicationLink.getBelowCompanyNo() != null,PlApplicationLink::getBelowCompanyNo,plApplicationLink.getBelowCompanyNo())
                    .like(plApplicationLink.getBelowCompanyName() != null,PlApplicationLink::getBelowCompanyName,plApplicationLink.getBelowCompanyName())
                    .eq(plApplicationLink.getBelowApplicationId() != null,PlApplicationLink::getBelowApplicationId,plApplicationLink.getBelowApplicationId())
                    .like(plApplicationLink.getBelowApplicationNo() != null,PlApplicationLink::getBelowApplicationNo,plApplicationLink.getBelowApplicationNo())
                    .like(plApplicationLink.getBelowApplicationName() != null,PlApplicationLink::getBelowApplicationName,plApplicationLink.getBelowApplicationName());
        }
        baseMapper.selectPage(pageParam,query);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deletePlApplicationLinkById(Long id) {
        //删除明细
        LambdaQueryWrapper<PlApplicationLinkDtl> update = Wrappers.lambdaQuery();
        update.eq(PlApplicationLinkDtl::getLinkId,id);
        plApplicationLinkDtlMapper.delete(update);
        //删除表头
        baseMapper.deleteById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPlApplicationLink(PlApplicationLink plApplicationLink) {
        //写入表头
        insertPlApplicationLink(plApplicationLink);
        //写入明细
        insertPlApplicationLinkDtl(plApplicationLink);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editPlApplicationLink(PlApplicationLink plApplicationLink) {
        //更新表头
        updatePlApplicationLink(plApplicationLink);
        //更新明细
        updatePlApplicationLinkDtl(plApplicationLink);
    }

    /**
     * 更新表头
     * @param plApplicationLink
     */
    private void updatePlApplicationLink(PlApplicationLink plApplicationLink) {
        //验证ID不能为空
        Assert.notNull(plApplicationLink.getId(),"id不能为空");
        //根据ID查询应用关联是否存在
        PlApplicationLink pl = baseMapper.selectById(plApplicationLink.getId());
        Assert.notNull(pl,"应用关联ID：" + plApplicationLink.getId() + "不存在");
        if(!StringUtils.hasText(plApplicationLink.getAboveApplicationNo())){
            plApplicationLink.setAboveApplicationNo(pl.getAboveApplicationNo());
        }
        if(!StringUtils.hasText(plApplicationLink.getBelowApplicationNo())){
            plApplicationLink.setBelowApplicationNo(pl.getBelowApplicationNo());
        }
        if(!pl.getAboveApplicationNo().equals(plApplicationLink.getAboveApplicationNo()) ||
                !pl.getBelowApplicationNo().equals(plApplicationLink.getBelowApplicationNo())){
            //验证上位应用与下位应用的关联关系必须唯一，重复则提示：应用关联关系【上位应用编号】【下位应用编号】已存在，请检查！
            checkPlApplicationLinkExists(plApplicationLink);
        }
        baseMapper.updateById(plApplicationLink);
    }

    /**
     * 更新明细
     * @param plApplicationLink
     */
    private void updatePlApplicationLinkDtl(PlApplicationLink plApplicationLink) {
        List<PlApplicationLinkDtl> items = plApplicationLink.getItems();
        if(CollectionUtils.isEmpty(items)){
            return;
        }
        for(PlApplicationLinkDtl item : items){
            //判断是新增还是更新
            if(item.getId() == null){
                //表头有数据取表头数据
                if(plApplicationLink.getCompanyId() != null){
                    item.setCompanyId(plApplicationLink.getCompanyId());
                }
                if(plApplicationLink.getId() != null){
                    item.setLinkId(plApplicationLink.getId());
                }
                addPlApplicationLinkDtl(item);
            }else{
                editPlApplicationLinkDtl(item);
            }
        }
    }

    /**
     * 写入表头
     * @param plApplicationLink
     */
    private void insertPlApplicationLink(PlApplicationLink plApplicationLink) {
        //验证表头非空字段
        checkPlApplicationLinkField(plApplicationLink);
        //验证上位应用与下位应用的关联关系必须唯一，重复则提示：应用关联关系【上位应用编号】【下位应用编号】已存在，请检查！
        checkPlApplicationLinkExists(plApplicationLink);
        baseMapper.insert(plApplicationLink);
    }

    /**
     * 写入明细
     * @param plApplicationLink
     */
    private void insertPlApplicationLinkDtl(PlApplicationLink plApplicationLink) {
        List<PlApplicationLinkDtl> items = plApplicationLink.getItems();
        Assert.notEmpty(items,"请维护应用环境关联关系后重试！");
        for(PlApplicationLinkDtl item : items){
            item.setCompanyId(plApplicationLink.getCompanyId());
            item.setLinkId(plApplicationLink.getId());
            addPlApplicationLinkDtl(item);
        }
    }

    /**
     * 验证应用关联非空字段
     * @param plApplicationLink
     */
    private void checkPlApplicationLinkField(PlApplicationLink plApplicationLink) {
        //验证字段非空
        Assert.notNull(plApplicationLink.getCompanyId(),"公司id不能为空");
        Assert.hasText(plApplicationLink.getLinkName(),"应用关联名称不能为空");
        Assert.notNull(plApplicationLink.getLinkStatus(),"应用关联状态不能为空");
//        Assert.notNull(plApplicationLink.getAboveCompanyId(),"上位公司id不能为空");
//        Assert.hasText(plApplicationLink.getAboveCompanyName(),"上位公司名称不能为空");
        Assert.notNull(plApplicationLink.getAboveApplicationId(),"上位应用id不能为空");
        Assert.hasText(plApplicationLink.getAboveApplicationNo(),"上位应用编号不能为空");
        Assert.hasText(plApplicationLink.getAboveApplicationName(),"上位应用名称不能为空");
//        Assert.notNull(plApplicationLink.getBelowCompanyId(),"下位公司id不能为空");
//        Assert.hasText(plApplicationLink.getBelowCompanyName(),"下位公司名称不能为空");
        Assert.notNull(plApplicationLink.getBelowApplicationId(),"下位应用id不能为空");
        Assert.hasText(plApplicationLink.getBelowApplicationNo(),"下位应用编号不能为空");
        Assert.hasText(plApplicationLink.getBelowApplicationName(),"下位应用名称不能为空");
    }

    /**
     * 验证应用关联明细非空字段
     * @param plApplicationLinkDtl
     */
    private void checkPlApplicationLinkDtlField(PlApplicationLinkDtl plApplicationLinkDtl) {
        //验证字段非空
        Assert.notNull(plApplicationLinkDtl.getCompanyId(),"公司id不能为空");
        Assert.notNull(plApplicationLinkDtl.getLinkId(),"应用关联明细id不能为空");
        Assert.notNull(plApplicationLinkDtl.getAboveEnvironmentId(),"上位环境id不能为空");
        Assert.hasText(plApplicationLinkDtl.getAboveEnvironmentName(),"上位环境名称不能为空");
        Assert.notNull(plApplicationLinkDtl.getBelowEnvironmentId(),"下位环境id不能为空");
        Assert.hasText(plApplicationLinkDtl.getBelowEnvironmentName(),"下位环境名称不能为空");
    }

    /**
     * 转化类型
     * @param plApplicationLinkDto
     * @return
     */
    @Override
    public PlApplicationLink convertPlApplicationLink(PlApplicationLinkDto plApplicationLinkDto) {
        PlApplicationLink plApplicationLink = new PlApplicationLink();
        BeanUtils.copyProperties(plApplicationLinkDto,plApplicationLink,"items");
        List<PlApplicationLinkDtlDto> items = plApplicationLinkDto.getItems();
        if(!CollectionUtils.isEmpty(items)){
            List<PlApplicationLinkDtl> dtls = new ArrayList<>();
            for(PlApplicationLinkDtlDto item : items){
            	
            	PlApplicationEnvironment aboE =	plApplicationEnvironmentMapper.selectById(item.getAboveEnvironmentId());
            	PlApplicationEnvironment bleE =	plApplicationEnvironmentMapper.selectById(item.getBelowEnvironmentId());
            	
                PlApplicationLinkDtl dtl = new PlApplicationLinkDtl();
                BeanUtils.copyProperties(item,dtl);
                dtl.setCompanyId(plApplicationLinkDto.getCompanyId());
                dtl.setAboveEnvironmentName(aboE.getEnvironmentName());
                dtl.setAboveEnvironmentNo(aboE.getEnvironmentNo());
                dtl.setBelowEnvironmentName(bleE.getEnvironmentName());
                dtl.setBelowEnvironmentNo(bleE.getEnvironmentNo());
                
                dtls.add(dtl);
            }
            plApplicationLink.setItems(dtls);
        }
        

        PlApplication aboApp = plApplicationMapper.selectById(plApplicationLinkDto.getAboveApplicationId());
        PlCompany aboCompany = Optional.ofNullable(plCompanyMapper.selectById(aboApp.getCompanyId())).orElse(new PlCompany());
        plApplicationLink.setAboveApplicationNo(aboApp.getApplicationNo());
        plApplicationLink.setAboveApplicationName(aboApp.getApplicationName());
        plApplicationLink.setAboveCompanyId(aboApp.getCompanyId());
        plApplicationLink.setAboveCompanyName(Optional.ofNullable(aboCompany.getCompanyName()).orElse(" "));
        plApplicationLink.setBelowCompanyNo(Optional.ofNullable(aboCompany.getCompanyNo()).orElse(" "));
       
        PlApplication belApp = plApplicationMapper.selectById(plApplicationLinkDto.getBelowApplicationId());
        PlCompany bleCompany = Optional.ofNullable(plCompanyMapper.selectById(belApp.getCompanyId())).orElse(new PlCompany());
        plApplicationLink.setBelowApplicationName(belApp.getApplicationName());
        plApplicationLink.setBelowApplicationNo(belApp.getApplicationNo());
        plApplicationLink.setBelowCompanyId(belApp.getCompanyId());
        plApplicationLink.setBelowCompanyName(Optional.ofNullable(bleCompany.getCompanyName()).orElse(" "));
        plApplicationLink.setBelowCompanyNo(Optional.ofNullable(bleCompany.getCompanyNo()).orElse(" "));
        
        return plApplicationLink;
    }

    @Override
    public void addPlApplicationLinkDtl(PlApplicationLinkDtl plApplicationLinkDtl) {
        //验证非空字段
        checkPlApplicationLinkDtlField(plApplicationLinkDtl);
        //验证应用环境关联关系是否重复
        checkPlApplicationLinkDtlExists(plApplicationLinkDtl);
        //查询表头是否存在
        //PlApplicationLink exists = baseMapper.selectById(plApplicationLinkDtl.getLinkId());
        //Assert.notNull(exists,"应用关联ID：" + plApplicationLinkDtl.getLinkId() + "不存在");
        plApplicationLinkDtlMapper.insert(plApplicationLinkDtl);
    }

    @Override
    public void editPlApplicationLinkDtl(PlApplicationLinkDtl plApplicationLinkDtl) {
        //验证非空字段
        Assert.notNull(plApplicationLinkDtl.getId(),"id不能为空");
        //checkPlApplicationLinkDtlField(plApplicationLinkDtl);
        PlApplicationLinkDtl pl = plApplicationLinkDtlMapper.selectById(plApplicationLinkDtl.getId());
        Assert.notNull(pl,"应用关联明细ID：" + plApplicationLinkDtl.getId() + "不存在");
        if(plApplicationLinkDtl.getAboveEnvironmentNo() == null){
            plApplicationLinkDtl.setAboveEnvironmentNo(pl.getAboveEnvironmentNo());
        }
        if(plApplicationLinkDtl.getBelowEnvironmentNo() == null){
            plApplicationLinkDtl.setBelowEnvironmentNo(pl.getBelowEnvironmentNo());
        }
        if(plApplicationLinkDtl.getAboveEnvironmentNo() != pl.getAboveEnvironmentNo() ||
                plApplicationLinkDtl.getBelowEnvironmentNo() != pl.getBelowEnvironmentNo()){
            checkPlApplicationLinkDtlExists(plApplicationLinkDtl);
        }
        plApplicationLinkDtlMapper.updateById(plApplicationLinkDtl);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deletePlApplicationLinkByIds(List<PlApplicationLinkDtlDto> list) {
        for(PlApplicationLinkDtlDto pl : list){
            baseMapper.deleteById(pl.getId());
            LambdaQueryWrapper<PlApplicationLinkDtl> delete = new LambdaQueryWrapper<>();
            delete.eq(PlApplicationLinkDtl::getLinkId,pl.getId());
            plApplicationLinkDtlMapper.delete(delete);
        }
    }

    /**
     * 验证应用关联是否重复
     * @param plApplicationLink
     */
    private void checkPlApplicationLinkExists(PlApplicationLink plApplicationLink) {
        //上位应用与下位应用的关联关系必须唯一，重复则提示：应用关联关系【上位应用编号】【下位应用编号】已存在，请检查！
        LambdaQueryWrapper<PlApplicationLink> query = Wrappers.lambdaQuery();
        query.eq(PlApplicationLink::getAboveApplicationNo,plApplicationLink.getAboveApplicationNo())
                .eq(PlApplicationLink::getBelowApplicationNo,plApplicationLink.getBelowApplicationNo());
        Long count = baseMapper.selectCount(query);
        Assert.isTrue(count < 1,"应用关联关系【上位应用编号】【下位应用编号】已存在，请检查");
    }

    /**
     * 验证应用环境关联关系是否重复
     * @param item
     */
    private void checkPlApplicationLinkDtlExists(PlApplicationLinkDtl item) {
        //应用环境关联关系在当前应用关联内必须唯一
        //A与B，A与C，不重复
        //A与B，B与A，重复
        //重复后提示：应用环境关联关系重复，请检查！
        LambdaQueryWrapper<PlApplicationLinkDtl> query = Wrappers.lambdaQuery();
        query.eq(PlApplicationLinkDtl::getAboveEnvironmentNo,item.getAboveEnvironmentNo())
                .eq(PlApplicationLinkDtl::getBelowEnvironmentNo,item.getBelowEnvironmentNo());
        Long count = plApplicationLinkDtlMapper.selectCount(query);
        Assert.isTrue(count < 1,"应用环境关联关系重复，请检查");
    }
}
